/*
    The NeonX Library

    Copyright (c) 2013 darkcat

    Code covered by the MIT License
*/

#pragma once

// nx...
#include "config/general.h"
// FixedPool
#include "memory/fixedpool.h"

//////////////////////////////////////////////////////////////////////////
NX_BEG
//////////////////////////////////////////////////////////////////////////

/*
    Default allocation parameters
*/

#ifndef NX_MEMPOOL_NUM
#define NX_MEMPOOL_NUM 256
#endif

#ifndef NX_MEMPOOL_INC
#define NX_MEMPOOL_INC sizeof(void*)
#endif

/*
    Scoped Memory Pool
*/

template
<
    size_t Num_ = NX_MEMPOOL_NUM, 
    size_t Inc_ = NX_MEMPOOL_INC, 

    typename Alloc_ = NX_ALLOC, 

    template
    <
        typename, 
        size_t, 
        template <typename, size_t> class
    >
    class Expand_ = MemExpandReturn     /* Memory growth model uses the MemExpandReturn */
>
class MemPool
{
public:
    typedef FixedPool<Alloc_, Expand_, NX_FIXEDPOOL_MODEL, 1> pool_t;

protected:
    pool_t* (pools_[Num_]);

    pool_t* find_pool(size_t size)
    {
        size_t n = ((size - 1) / Inc_);
        if (n >= Num_) return NX_NULL;
        return pools_[n];
    }

public:
    MemPool(void)
    {
        size_t n = Inc_;
        nx_foreach(i, Num_, n += Inc_)
            pools_[i] = nx::alloc<Alloc_, pool_t>(n);
    }
    virtual ~MemPool()
    {
        nx_foreach(i, Num_)
            nx::free<Alloc_>(pools_[i]);
    }

public:
    pvoid alloc(size_t size)
    {
        if (size == 0) return NX_NULL;
        pool_t* pool = find_pool(size);
        if (pool)
            return pool->alloc();
        else
            return nx::alloc<Alloc_, void>(size);
    }

    void free(pvoid p, size_t size)
    {
        if (!p || (size == 0)) return;
        pool_t* pool = find_pool(size);
        if (pool)
            pool->free(p);
        else
            nx::free<Alloc_>(p, size);
    }
};

//////////////////////////////////////////////////////////////////////////
NX_END
//////////////////////////////////////////////////////////////////////////
